Skip to content

fix(backend): GitHub API レート制限の 403 をリトライせず握り込む不具合を修正(#485)#487

Merged
yusuke0610 merged 2 commits into
mainfrom
fix/github-tree-ratelimit-403
Jul 12, 2026
Merged

fix(backend): GitHub API レート制限の 403 をリトライせず握り込む不具合を修正(#485)#487
yusuke0610 merged 2 commits into
mainfrom
fix/github-tree-ratelimit-403

Conversation

@yusuke0610

@yusuke0610 yusuke0610 commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

fetch_repo_tree が GitHub API のレート制限(403 + X-RateLimit-Remaining:0 / 429)を「1 リポの部分走査(partial)」として黙って握り込み、リトライされずスキル証跡が静かに欠けていた不具合を修正しました(#485#478 の実データ計測中に発見した既知事項の follow-up)。

  • fetch_repos_raw に既にあったレート制限判別ロジックを共通ヘルパ _raise_if_rate_limited に抽出
  • fetch_repo_tree / fetch_languages / fetch_repo_file(同一ホットパスの兄弟 fetch)の全経路でレート制限を RetryableErrorretry_after 付き)として統一し、連携タスク全体をリトライさせる
  • レート制限でない 403(権限エラー等)は従来どおり best-effort(partial / 空返却)を維持

Test Plan

  • TDD(red→green): レート制限 403→Retryable / 429→Retryable / 権限 403→partial / languages のレート制限→Retryable の回帰テストを追加
  • make ci pass(lint / typecheck / test / build)
  • fetch_repos_raw の既存リトライ挙動(test_retry_flow.py 等 88 件)に回帰なし

Notes

  • スキーマ・API 契約は不変(migration / codegen 不要)
  • issue に名指しだった fetch_repo_tree に加え、同じ握り込みバグを持つ fetch_languages / fetch_repo_file も同一 PR で修正(tree だけ直すと mid-repo でのレート制限時に同じ問題が残るため)

Closes #485

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of GitHub API rate limits so requests now retry instead of returning incomplete or empty results.
    • Better distinguishes true permission errors from temporary throttling, reducing unexpected failures during repository syncs and data collection.
    • Added support for retry timing based on GitHub’s response headers to make retries more accurate.

fetch_repo_tree が rate-limit の 403 を partial 走査として黙って握り込み、
リトライされずスキル証跡が欠けていた問題を修正。fetch_repos_raw の判別ロジックを
共通ヘルパ(_raise_if_rate_limited)に抽出し、fetch_repo_tree / fetch_languages /
fetch_repo_file の GitHub API 呼び出し全経路で RetryableError に統一した。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yusuke0610, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 522845f1-d125-4e3f-afd9-c2d6707d006c

📥 Commits

Reviewing files that changed from the base of the PR and between 0531a29 and c05c7fe.

📒 Files selected for processing (1)
  • backend/tests/test_github_api_client.py
📝 Walkthrough

Walkthrough

Refactors GitHub API client rate-limit handling by introducing a shared _raise_if_rate_limited helper that detects 403 (with zero remaining quota) and 429 responses, raising RetryableError with retry-after timing. Applies this helper across fetch_repos_raw, fetch_languages, fetch_repo_tree, and fetch_repo_file, and adds corresponding tests.

Changes

Rate-limit retry handling in GitHub API client

Layer / File(s) Summary
Rate-limit detection helper and fetch_repos_raw integration
backend/app/services/intelligence/github/api_client.py
Expands _is_rate_limited to distinguish 403 vs 429 via headers/status, adds _raise_if_rate_limited to log rate-limit details and raise RetryableError with retry_after, and refactors fetch_repos_raw to use this shared helper instead of inline branching.
Apply rate-limit helper to remaining fetch functions
backend/app/services/intelligence/github/api_client.py
Wires _raise_if_rate_limited into fetch_languages, fetch_repo_tree, and fetch_repo_file before existing 403/non-200 handling, updates comments and warning text so rate limits trigger task-level retry instead of silent partial/empty results.
Rate-limit regression tests
backend/tests/test_github_api_client.py
Adds pytest, fetch_languages, and RetryableError imports, a _client_with_status mock helper with configurable status/headers, and new tests validating RetryableError on rate-limited 403/429 and partial/empty results on genuine 403 for fetch_repo_tree and fetch_languages.

Estimated code review effort: 2 (Simple) | ~15 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant fetch_repo_tree
  participant _raise_if_rate_limited
  participant GitHubAPI

  Caller->>fetch_repo_tree: request repo tree
  fetch_repo_tree->>GitHubAPI: GET /repos/{owner}/{repo}/git/trees/{branch}
  GitHubAPI-->>fetch_repo_tree: response (status, headers)
  fetch_repo_tree->>_raise_if_rate_limited: check response
  alt rate limited (403 remaining=0 or 429)
    _raise_if_rate_limited-->>Caller: raise RetryableError(retry_after)
  else genuine 403 or non-200
    _raise_if_rate_limited-->>fetch_repo_tree: no error
    fetch_repo_tree-->>Caller: return ([], True) with warning
  else success
    fetch_repo_tree-->>Caller: return parsed tree
  end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main backend fix for GitHub rate-limit 403 handling.
Linked Issues check ✅ Passed The changes satisfy #485: rate-limit 403/429 now raise RetryableError, genuine 403s remain best-effort, and regression tests cover both paths.
Out of Scope Changes check ✅ Passed The added fetch_languages/fetch_repo_file handling and tests are all aligned with the stated GitHub rate-limit fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/github-tree-ratelimit-403

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
backend/tests/test_github_api_client.py (1)

91-130: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Tests look solid for fetch_repo_tree and fetch_languages.

One minor gap: _raise_if_rate_limited was also wired into fetch_repo_file (line 263), but no regression test covers that path. Consider adding a test mirroring the fetch_repo_tree pattern to verify rate-limited 403/429 raises RetryableError and genuine 403 returns None.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_github_api_client.py` around lines 91 - 130, Add
regression coverage for the `fetch_repo_file` path, since it also calls
`_raise_if_rate_limited` but is not exercised here. Mirror the existing
`fetch_repo_tree`/`fetch_languages` style in `test_github_api_client.py` by
adding tests that confirm `fetch_repo_file` raises `RetryableError` for
rate-limited 403/429 responses and still returns `None` for a genuine 403 with
remaining quota. Use the existing helpers like `_client_with_status` and `_run`
to keep the new tests consistent with the current suite.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@backend/tests/test_github_api_client.py`:
- Around line 91-130: Add regression coverage for the `fetch_repo_file` path,
since it also calls `_raise_if_rate_limited` but is not exercised here. Mirror
the existing `fetch_repo_tree`/`fetch_languages` style in
`test_github_api_client.py` by adding tests that confirm `fetch_repo_file`
raises `RetryableError` for rate-limited 403/429 responses and still returns
`None` for a genuine 403 with remaining quota. Use the existing helpers like
`_client_with_status` and `_run` to keep the new tests consistent with the
current suite.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: dd0cc1dd-8f83-4dff-971c-c19593ff6430

📥 Commits

Reviewing files that changed from the base of the PR and between 29f09fe and 0531a29.

📒 Files selected for processing (2)
  • backend/app/services/intelligence/github/api_client.py
  • backend/tests/test_github_api_client.py

@github-actions github-actions Bot added backend バックエンド bug バグ修正 test テスト追加・修正 labels Jul 9, 2026
fetch_repo_file も _raise_if_rate_limited を呼ぶが未テストだったため、
fetch_repo_tree / fetch_languages と同じスタイルで
- レート制限 403 → RetryableError
- 429 → RetryableError
- 権限 403(残量あり)→ None(当該 manifest スキップ)
の 3 ケースを追加。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yusuke0610
yusuke0610 merged commit 8d7cdc6 into main Jul 12, 2026
20 checks passed
@yusuke0610
yusuke0610 deleted the fix/github-tree-ratelimit-403 branch July 20, 2026 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend バックエンド bug バグ修正 test テスト追加・修正

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(backend): fetch_repo_tree が rate-limit の 403 をリトライせず黙って partial 扱いにする(ADR-0016 D9)

1 participant